
#include "RtBase.h"
#include "RtHttpProxyInfoGetter.h"
#include "RtHttpProxySetting.h"
#include "RtHttpProxyManager.h"

#ifdef RT_WIN32
#include "RtHttpJsEngine.h"
#include "RtHttpUrl.h"
#include "RtMessageBlock.h"
#include "RtObserver.h"
#include <stack>
using namespace std;

//////////////////////////////////////////////////////////////////////
// class CPacResultAnaly
//////////////////////////////////////////////////////////////////////

class CPacResultAnaly
{
public:
	CPacResultAnaly(char* pacResult);
	virtual ~CPacResultAnaly();
	
	void Set(char* pacResult);
	BOOL GetAProxy(CRtString &aProxy, CRtHttpProxyInfo::PROXY_TYPE& aType);
private:
	char* m_pPacResult;
	LPCSTR m_pPos;
};

CPacResultAnaly::CPacResultAnaly(char* pacResult)
{
	m_pPacResult = NULL;
	Set(pacResult);
}

CPacResultAnaly::~CPacResultAnaly()
{
	if(m_pPacResult)
	{
		delete []m_pPacResult;
		m_pPacResult = NULL;
	}
}

void CPacResultAnaly::Set(char* pacResult)
{
	if(m_pPacResult)
		delete []m_pPacResult;

	m_pPacResult = pacResult;
	m_pPos = m_pPacResult;
}

BOOL CPacResultAnaly::
GetAProxy(CRtString &aProxy, CRtHttpProxyInfo::PROXY_TYPE& aType)
{
	BOOL bRet = FALSE;
	while (m_pPos && *m_pPos)
	{
		while (isspace(*m_pPos) || *m_pPos == ';')
			m_pPos++;
		if (*m_pPos == '\0')
			break;

		LPCSTR pEnd = strchr(m_pPos, ';');
		if (!pEnd)
			pEnd = m_pPos + strlen(m_pPos);

		if (!strncasecmp(m_pPos,"DIRECT", 6))
		{
			m_pPos += 6;
			while (isspace(*m_pPos)) 
				m_pPos++;

			if (*m_pPos == '\0' || *m_pPos == ';') {
				RT_INFO_TRACE_THIS("CPacResultAnaly::GetAProxy, got \"DIRECT\"...");
				aProxy.resize(0);
				aType = CRtHttpProxyInfo::HTTP_PROXY;
				bRet = TRUE;
			}
		}
		else if ((!strncasecmp(m_pPos, "PROXY", 5) || !strncasecmp(m_pPos, "SOCKS", 5))
			&& isspace(m_pPos[5]))
		{
			if (strncasecmp(m_pPos, "SOCKS", 5) == 0)
				aType = CRtHttpProxyInfo::SOCK4_PROXY;
			else
				aType = CRtHttpProxyInfo::HTTP_PROXY;

			m_pPos += 5;
			while (isspace(*m_pPos)) 
				m_pPos++;
			if (*m_pPos) {
				aProxy.assign(m_pPos, pEnd - m_pPos);
				if (!aProxy.empty())
					bRet = TRUE;
			}
		}

		m_pPos = pEnd;
		if (bRet)
			break;
	}
	return bRet;
}


//////////////////////////////////////////////////////////////////////
// class CRtHttpProxyInfoGetterFileBase
//////////////////////////////////////////////////////////////////////

CRtHttpProxyInfoGetterFileBase::CRtHttpProxyInfoGetterFileBase(IRtObserver *aObserver)
	: m_dwState(DOWNLOADING)
	, m_pObserver(aObserver)
	, m_dwRetryCount(0)
{
	RT_ASSERTE(m_pObserver);
	m_FileChannel.AddReference();
}

CRtHttpProxyInfoGetterFileBase::~CRtHttpProxyInfoGetterFileBase()
{
	if (m_pHttpChannel) {
		m_pHttpChannel->Disconnect(RT_OK);
		m_pHttpChannel = NULL;
	}
}

DWORD CRtHttpProxyInfoGetterFileBase::AddReference()
{
	return CRtReferenceControlMutilThread::AddReference();
}

DWORD CRtHttpProxyInfoGetterFileBase::ReleaseReference()
{
	return CRtReferenceControlMutilThread::ReleaseReference();
}

RtResult CRtHttpProxyInfoGetterFileBase::StartUp(const CRtString &aData)
{
	RtResult rv;
	RT_INFO_TRACE_THIS("CRtHttpProxyInfoGetterFileBase::StartUp, aData=" << aData);
	RT_ASSERTE_RETURN(!aData.empty(), RT_ERROR_INVALID_ARG);
	RT_ASSERTE(!m_pHttpChannel);

	CRtChannelManager *pChannelManager = CRtChannelManager::Instance();
	RT_ASSERTE(pChannelManager);

	CRtAutoPtr<CRtHttpUrl> pURL;
	rv = pChannelManager->CreateUrl(pURL.ParaOut(), aData);
	if (RT_FAILED(rv))
		return rv;

	IRtChannel *pChannel = NULL;
	if (pURL->GetScheme() == CRtHttpUrl::s_pszSchemeFile) {
		if (!m_FileChannel.Init(pURL.ParaIn()))
			return RT_ERROR_FAILURE;
		pChannel = &m_FileChannel;
	}
	else {
		rv = pChannelManager->CreateChannelHttpClient(
			m_pHttpChannel.ParaOut(), 
			pURL.ParaIn(),
			0);
		if (RT_FAILED(rv))
			return rv;
		pChannel = m_pHttpChannel.Get();
		
		// allow downloading time 120s.
		m_TimerClose.Schedule(this, CRtTimeValue(120, 0), 1);
	}
	m_dwState = DOWNLOADING;

	rv = pChannel->AsyncOpen(this);
	if (RT_FAILED(rv)) {
		m_dwState = DOWNLOAD_FAILED;
		pChannel->Disconnect(rv);
		m_pHttpChannel = NULL;
	}
	m_strUrl = aData;
	return rv;
}

void CRtHttpProxyInfoGetterFileBase::
OnConnect(RtResult aReason, IRtChannel *aChannelId)
{
	if (RT_SUCCEEDED(aReason)) {
		if (m_pHttpChannel.Get() == aChannelId) {
			CRtMessageBlock mbZero(0UL);
			aReason = m_pHttpChannel->SendData(mbZero);
			RT_ASSERTE(RT_SUCCEEDED(aReason));
			if (RT_SUCCEEDED(aReason))
				return;
		}
		else if (&m_FileChannel == aChannelId) {
			return;
		}
	}

	RT_ASSERTE(RT_FAILED(aReason));
	OnDisconnect(aReason, aChannelId);
}

void CRtHttpProxyInfoGetterFileBase::
OnReceive(CRtMessageBlock &aData, IRtTransport *aTrptId, 
		  CRtTransportParameter *aPara)
{
	RtResult rv = RT_OK;
	if (m_pHttpChannel.Get() == aTrptId) {
		LONG lState = 0;
		rv = m_pHttpChannel->GetResponseStatus(lState);
		RT_ASSERTE(RT_SUCCEEDED(rv));

		RT_INFO_TRACE_THIS("CRtHttpProxyInfoGetterFileBase::OnReceive,"
			" len=" << aData.GetChainedLength() << 
			" lState=" << lState << 
			" m_dwState=" << m_dwState);

		rv = RT_ERROR_FAILURE;
		if (lState == 200 && aData.GetChainedLength() > 0) {
			m_dwState = DOWNLOAD_SUCCESS;
			m_pHttpChannel->Disconnect(RT_OK);
			m_pHttpChannel = NULL;
			m_TimerClose.Cancel();

			rv = OnReceiveResonpse(aData);
		}
	}
	else if (&m_FileChannel == aTrptId) {
		m_dwState = DOWNLOAD_SUCCESS;
		m_FileChannel.Disconnect(RT_OK);
		m_TimerClose.Cancel();

		rv = OnReceiveResonpse(aData);
	}

	if (RT_FAILED(rv)) {
		OnDisconnect(rv, aTrptId);
	}
}

void CRtHttpProxyInfoGetterFileBase::
OnSend(IRtTransport *aTrptId, CRtTransportParameter *aPara)
{
	RT_ASSERTE(!"CRtHttpProxyInfoGetterFileBase::OnSend");
}

void CRtHttpProxyInfoGetterFileBase::
OnDisconnect(RtResult aReason, IRtTransport *aTrptId)
{
	RT_INFO_TRACE_THIS("CRtHttpProxyInfoGetterFileBase::OnDisconnect,"
		" aReason=" << aReason << 
		" m_dwState=" << m_dwState << 
		" m_dwRetryCount=" << m_dwRetryCount);

//	RT_ASSERTE(m_pHttpChannel.Get() == aTrptId);
	m_FileChannel.Disconnect(aReason);
	if (m_pHttpChannel) {
		m_pHttpChannel->Disconnect(aReason);
		m_pHttpChannel = NULL;
	}
	m_TimerClose.Cancel();

	if (m_pHttpChannel.Get() == aTrptId && ++m_dwRetryCount <= 5) {
		RtResult rv = StartUp(m_strUrl);
		if (RT_SUCCEEDED(rv))
			return;
	}

	RT_ASSERTE(m_dwState != DOWNLOAD_SUCCESS);
	m_dwState = DOWNLOAD_FAILED;
	
	if (m_pObserver) {
		m_pObserver->OnObserve("HttpProxyInfoGetterFile", this);
		m_pObserver = NULL;
	}
}

void CRtHttpProxyInfoGetterFileBase::OnTimer(CRtTimerWrapper* aId)
{
	RT_ASSERTE(&m_TimerClose == aId);
	OnDisconnect(RT_ERROR_TIMEOUT, m_pHttpChannel.ParaIn());
}


//////////////////////////////////////////////////////////////////////
// class CRtHttpProxyInfoGetterPacFile
//////////////////////////////////////////////////////////////////////

CRtHttpProxyInfoGetterPacFile::CRtHttpProxyInfoGetterPacFile(IRtObserver *aObserver)
	: CRtHttpProxyInfoGetterFileBase(aObserver)
	, m_pPacAnalyzer(NULL)
{
}

CRtHttpProxyInfoGetterPacFile::~CRtHttpProxyInfoGetterPacFile()
{
	delete m_pPacAnalyzer;
}

RtResult CRtHttpProxyInfoGetterPacFile::OnReceiveResonpse(CRtMessageBlock &aData)
{
	m_strPacFile = aData.FlattenChained();
	if (m_pObserver) {
		m_pObserver->OnObserve("HttpProxyInfoGetterFile", this);
		m_pObserver = NULL;
	}
	return RT_OK;
}

IRtHttpProxyInfoGetter::NextReturn CRtHttpProxyInfoGetterPacFile::
GetNextProxyInfo(const CRtString &aHost, WORD aPort, CRtHttpProxyInfo* &aPi)
{
	if (m_dwState == DOWNLOADING)
		return NEXT_WOULDBLCOK;
	if (m_dwState == DOWNLOAD_FAILED)
		return NEXT_FAILED;

	if (!m_pPacAnalyzer && !Reset(aHost, aPort))
		return NEXT_FAILED;

	CRtString strProxy;
	CRtHttpProxyInfo::PROXY_TYPE nType;
	while (m_pPacAnalyzer->GetAProxy(strProxy, nType)) 
	{
		if (CRtHttpProxyManager::Instance()->CreateProxyInfo(strProxy, nType, aPi))
		{
			return NEXT_SUCCESS;
		}
	}
	return NEXT_FAILED;
}

BOOL CRtHttpProxyInfoGetterPacFile::Reset(const CRtString &aHost, WORD aPort)
{
	BOOL bRet = FALSE;
	if (m_dwState != DOWNLOAD_SUCCESS)
		return bRet;

	delete m_pPacAnalyzer;
	m_pPacAnalyzer = NULL;

	RT_INFO_TRACE_THIS("CRtHttpProxyInfoGetterPacFile::Reset,"
		" m_strPacFile=" << m_strPacFile);

	CIWLAutoConfigJSParser jsParser;
	if (jsParser.Init() == 0 && jsParser.SetPacScript(m_strPacFile.c_str()) == 0) {
		char* proxyresult;
		CRtString strUrl;
		if (aPort == 443)	
			strUrl = "https://";
		else
			strUrl = "http://";
		strUrl += aHost;
		if (jsParser.FindProxyFromURL(strUrl.c_str(), aHost.c_str(), proxyresult) != 0) {
//			RT_ERROR_TRACE_THIS("CRtHttpProxyInfoGetterPacFile::Reset,"
//				" FindProxyFromURL failed! strUrl=" << strUrl);
			return FALSE;
		}
		m_pPacAnalyzer = new CPacResultAnaly(proxyresult);
		if (m_pPacAnalyzer)
			bRet = TRUE;
	}
	else {
//		RT_ERROR_TRACE_THIS("CRtHttpProxyInfoGetterPacFile::Reset, jsParser.SetPacScript failed!");
	}
	return bRet;
}


//////////////////////////////////////////////////////////////////////
// class CRtHttpProxyInfoGetterInsFile
//////////////////////////////////////////////////////////////////////

CRtHttpProxyInfoGetterInsFile::CRtHttpProxyInfoGetterInsFile(IRtObserver *aObserver)
	: CRtHttpProxyInfoGetterFileBase(aObserver)
{
}

CRtHttpProxyInfoGetterInsFile::~CRtHttpProxyInfoGetterInsFile()
{
}

static RtResult GetValueByKey_s(const CRtString &aSection, LPCSTR aKey, CRtString &aValue)
{
	CRtString strKey(aKey);
	strKey += '=';
	CRtString::size_type nFind = aSection.find(strKey);
	if (nFind == CRtString::npos) 
		return RT_ERROR_NOT_FOUND;

	nFind += strKey.length();
	CRtString::size_type nFind2 = aSection.find('\n', nFind);
	if (nFind2 == CRtString::npos)
		aValue = aSection.substr(nFind);
	else {
		if (aSection[nFind2 - 1] == '\r')
			nFind2--;
		aValue = aSection.substr(nFind, nFind2 - nFind);
	}
	return RT_OK;
}

RtResult CRtHttpProxyInfoGetterInsFile::OnReceiveResonpse(CRtMessageBlock &aData)
{
	RtResult rv;
	CRtString strIns = aData.FlattenChained();
	CRtString strAutoConfig;
	rv = GetValueByKey_s(strIns, "AutoConfig", strAutoConfig);
	if (RT_FAILED(rv)) {
		RT_ERROR_TRACE_THIS("CRtHttpProxyInfoGetterInsFile::OnReceiveResonpse,"
			" can't find AutoConfig. strIns=" << strIns);
		return rv;
	}

	int nAutoConfig = ::atoi(strAutoConfig.c_str());
	if (nAutoConfig != 1) {
		RT_ERROR_TRACE_THIS("CRtHttpProxyInfoGetterInsFile::OnReceiveResonpse,"
			" nAutoConfig=" << nAutoConfig);
		return RT_ERROR_INVALID_ARG;
	}

	CRtString strJSURL;
	rv = GetValueByKey_s(strIns, "AutoConfigJSURL", strJSURL);
	if (RT_FAILED(rv)) {
		RT_ERROR_TRACE_THIS("CRtHttpProxyInfoGetterInsFile::OnReceiveResonpse,"
			" can't find AutoConfigJSURL. strIns=" << strIns);
		return rv;
	}

	RT_ASSERTE(!m_pProxyInfoGetterPacFile);
	m_pProxyInfoGetterPacFile = new CRtHttpProxyInfoGetterPacFile(this);
	rv = m_pProxyInfoGetterPacFile->StartUp(strJSURL);
	if (RT_FAILED(rv))
		m_pProxyInfoGetterPacFile = NULL;
	return rv;
}

IRtHttpProxyInfoGetter::NextReturn CRtHttpProxyInfoGetterInsFile::
GetNextProxyInfo(const CRtString &aHost, WORD aPort, CRtHttpProxyInfo* &aPi)
{
	if (m_dwState == DOWNLOADING)
		return NEXT_WOULDBLCOK;
	if (m_dwState == DOWNLOAD_FAILED)
		return NEXT_FAILED;

	if (m_pProxyInfoGetterPacFile)
		return m_pProxyInfoGetterPacFile->GetNextProxyInfo(aHost, aPort, aPi);
	else
		return NEXT_FAILED;
}

BOOL CRtHttpProxyInfoGetterInsFile::Reset(const CRtString &aHost, WORD aPort)
{
	if (m_dwState != DOWNLOAD_SUCCESS)
		return FALSE;

	if (m_pProxyInfoGetterPacFile)
		return m_pProxyInfoGetterPacFile->Reset(aHost, aPort);
	else
		return FALSE;
}

void CRtHttpProxyInfoGetterInsFile::OnObserve(LPCSTR aTopic, LPVOID aData)
{
	RT_ASSERTE(m_pProxyInfoGetterPacFile);
	if (m_pObserver)
		m_pObserver->OnObserve(aTopic, this);
}


/////////////////////////////////////////////////////////////
// class CRtHttpProxyInfoGetterManual
/////////////////////////////////////////////////////////////

CRtHttpProxyInfoGetterManual::CRtHttpProxyInfoGetterManual()
{
	Reset(CRtString(), 0);
}

CRtHttpProxyInfoGetterManual::~CRtHttpProxyInfoGetterManual()
{
}

DWORD CRtHttpProxyInfoGetterManual::AddReference()
{
	return CRtReferenceControlMutilThread::AddReference();
}

DWORD CRtHttpProxyInfoGetterManual::ReleaseReference()
{
	return CRtReferenceControlMutilThread::ReleaseReference();
}

RtResult CRtHttpProxyInfoGetterManual::StartUp(const CRtString &aData)
{
	m_strManual = aData;
	return m_strManual.empty() ? RT_ERROR_INVALID_ARG : RT_OK;
}

BOOL CRtHttpProxyInfoGetterManual::Reset(const CRtString &aHost, WORD aPort)
{
	m_FindPos = FIND_HTTPS;
	return TRUE;
}

IRtHttpProxyInfoGetter::NextReturn CRtHttpProxyInfoGetterManual::
GetNextProxyInfo(const CRtString &aHost, WORD aPort, CRtHttpProxyInfo* &aPi)
{
	if (IsByPass(aHost, aPort)) {
//		INFOTRACE("CRtHttpProxyInfoGetterManual::GetNextProxyInfo, IsByPass. aHost=" << aHost.c_str());
		aPi = NULL;
		return NEXT_SUCCESS;
	}

	CRtString strBuf;
	CRtHttpProxyInfo::PROXY_TYPE type;
	do {
		MoveNext(strBuf, type);
		if (!strBuf.empty() && 
			CRtHttpProxyManager::Instance()->CreateProxyInfo(strBuf, type, aPi)) 
		{
			return NEXT_SUCCESS;
		}
	} while (!strBuf.empty());
	
	return NEXT_FAILED;
}

void CRtHttpProxyInfoGetterManual::
MoveNext(CRtString &aBuf, CRtHttpProxyInfo::PROXY_TYPE &aType)
{
	int pos1, pos2;
	aBuf.resize(0);
	while (aBuf.empty())
	{
		switch(m_FindPos) {
		case FIND_HTTPS:
			if((pos1 = m_strManual.find("https=")) != -1)
			{
				aType = CRtHttpProxyInfo::HTTPS_PROXY;
				pos1 += 6;
				pos2 = m_strManual.find(';', pos1);
				if(pos2 != -1)
					aBuf = m_strManual.substr(pos1, pos2 - pos1);
				else
					aBuf = m_strManual.substr(pos1);
			}
			m_FindPos = FIND_HTTP;
			break;
		case FIND_HTTP:
			if((pos1 = m_strManual.find("http=")) != -1)
			{
				aType = CRtHttpProxyInfo::HTTP_PROXY;
				pos1 += 5;
				pos2 = m_strManual.find(';', pos1);
				if(pos2 != -1)
					aBuf = m_strManual.substr(pos1, pos2 - pos1);
				else
					aBuf = m_strManual.substr(pos1);
			}
			m_FindPos = FIND_SOCKS;
			break;
		case FIND_SOCKS:
			pos1 = m_strManual.find("socks=");
			if(pos1 == -1)
			{
				pos1 = m_strManual.find("socks5=");
				if(pos1 != -1)
				{
					pos1 += 7;
					aType = CRtHttpProxyInfo::SOCK5_PROXY;
				}
			}
			else
			{
				pos1 += 6;
				aType = CRtHttpProxyInfo::SOCK4_PROXY;
			}
			
			if(-1 != pos1)
			{
				pos2 = m_strManual.find(';', pos1);
				if(pos2 != -1)
					aBuf = m_strManual.substr(pos1, pos2 - pos1);
				else
					aBuf = m_strManual.substr(pos1);
			}
			m_FindPos = FIND_NONE;
			break;
		default:
			return;
		}
	}
}

class CWbxHByPassBase
{
public:
	CWbxHByPassBase(const CRtHttpProxyInfoGetterManual::CByPassEntry &aEntry)
		: m_entnyGiven(aEntry)
	{ }
protected:
	const CRtHttpProxyInfoGetterManual::CByPassEntry &m_entnyGiven;
};

class CWbxHIEByPass : public CWbxHByPassBase
{
public:
	CWbxHIEByPass(const CRtHttpProxyInfoGetterManual::CByPassEntry &aEntry)
		: CWbxHByPassBase(aEntry)
	{ }

	typedef pair<LPCSTR, LPCSTR> EleType;

	bool operator() (const CRtHttpProxyInfoGetterManual::CByPassEntry &aRight) const
	{
		stack< EleType, vector<EleType> > stackPoint;
		LPCSTR pszNext = NULL;
		LPCSTR pszLeft = m_entnyGiven.m_strHost.c_str();
		LPCSTR pszRight = aRight.m_strHost.c_str();
		while (*pszLeft && *pszRight) {
			if (*pszRight == '*') {
				while (*pszRight == '*') 
					pszRight++;
				pszNext = pszRight;
			}
			if (pszNext) {
				if (!*pszNext) 
					return true;
				if (*pszNext == *pszLeft) {
					pszNext = NULL;
					stackPoint.push(EleType(pszLeft, pszRight));
					++pszRight;
				}
				++pszLeft;
			} else {
				if (*pszLeft != *pszRight) {
					if (stackPoint.empty())
						return false;
					EleType ele = stackPoint.top();
					pszLeft = ele.first + 1;
					pszRight = ele.second;
					stackPoint.pop();
					pszNext = pszRight;
				} else {
					++pszLeft;
					++pszRight;
				}
			}
		}
		return (!*pszLeft && !*pszRight);
	}
};

class CWbxHMozillaByPass : public CWbxHByPassBase
{
public:
	CWbxHMozillaByPass(const CRtHttpProxyInfoGetterManual::CByPassEntry &aEntry)
		: CWbxHByPassBase(aEntry)
	{ }

	bool operator() (const CRtHttpProxyInfoGetterManual::CByPassEntry &aFilter) const
	{
		bool bRet = false;
		if ((aFilter.m_wPort == 0 || m_entnyGiven.m_wPort == aFilter.m_wPort) 
			&& !m_entnyGiven.m_strHost.empty()
			&& m_entnyGiven.m_strHost.length() >= aFilter.m_strHost.length())
		{
			LPCSTR pMove = m_entnyGiven.m_strHost.c_str();
			if (aFilter.m_strHost[0] == '.')
				pMove = m_entnyGiven.m_strHost.c_str() + m_entnyGiven.m_strHost.length() - aFilter.m_strHost.length();
			if (!stricmp(pMove, aFilter.m_strHost.c_str()))
				bRet = true;
		}
		return bRet;
	}
};

BOOL CRtHttpProxyInfoGetterManual::IsByPass(const CRtString &aIpaddress, WORD aPort) 
{
	CByPassEntry newEntry(aIpaddress, aPort);
	CByPassEntrysType::const_iterator iter;
	if (m_BrowserType == IRtHttpProxySetting::BROWSER_IE)
		iter = find_if(m_ByPassArray.begin(), m_ByPassArray.end(), CWbxHIEByPass(newEntry));
	else
		iter = find_if(m_ByPassArray.begin(), m_ByPassArray.end(), CWbxHMozillaByPass(newEntry));
	return (iter == m_ByPassArray.end()) ? FALSE : TRUE;
}

void CRtHttpProxyInfoGetterManual::
SetBypass(const CRtString &aBypass, IRtHttpProxySetting::BrowseType aType)
{
	m_BrowserType = aType;
	m_strBypass = aBypass;
	m_ByPassArray.clear();
	LPCSTR pSrc = m_strBypass.c_str();

	while (*pSrc) {
		while (*pSrc && (*pSrc == ',' || *pSrc == ';' || isspace(*pSrc)))
            pSrc++;
		if (!*pSrc)
			break;

        LPCSTR endproxy = pSrc + 1;
        LPCSTR portLocation = NULL; 
        int nport = 0;
        while (*endproxy && (*endproxy != ',' && *endproxy != ';' && !isspace(*endproxy)))
        {
            if (*endproxy == ':')
                portLocation = endproxy;
            endproxy++;
        }
        if (portLocation)
            nport = atoi(portLocation+1);

		CByPassEntry newEntry(CRtString(pSrc, endproxy - pSrc), nport);
		m_ByPassArray.push_back(newEntry);

        pSrc = endproxy;
	}
}
#endif // RT_WIN32


//////////////////////////////////////////////////////////////////////
// class CRtHttpProxyInfoGetterByUpperLayer
//////////////////////////////////////////////////////////////////////

CRtHttpProxyInfoGetterByUpperLayer* CRtHttpProxyInfoGetterByUpperLayer::Instance()
{
	return CRtSingletonT<CRtHttpProxyInfoGetterByUpperLayer>::Instance();
}

CRtHttpProxyInfoGetterByUpperLayer::CRtHttpProxyInfoGetterByUpperLayer()
	: m_nIndex(0)
	, m_pObserver(NULL)
{
	RT_INFO_TRACE_THIS("CRtHttpProxyInfoGetterByUpperLayer::CRtHttpProxyInfoGetterByUpperLayer");
	m_pType[0] = CRtHttpProxyInfo::HTTP_PROXY;
	m_pType[1] = CRtHttpProxyInfo::HTTPS_PROXY;
}

CRtHttpProxyInfoGetterByUpperLayer::~CRtHttpProxyInfoGetterByUpperLayer()
{
}

DWORD CRtHttpProxyInfoGetterByUpperLayer::AddReference()
{
	return 1;
}

DWORD CRtHttpProxyInfoGetterByUpperLayer::ReleaseReference()
{
	return 1;
}

RtResult CRtHttpProxyInfoGetterByUpperLayer::StartUp(const CRtString &aData)
{
	return RT_OK;
}

BOOL CRtHttpProxyInfoGetterByUpperLayer::Reset(const CRtString &aHost, WORD aPort)
{
	for (int i = 0; i < MAX_INDEX; i++)
		m_pServerIp[i].resize(0);
	m_nIndex = 0;
	return TRUE;
}

IRtHttpProxyInfoGetter::NextReturn CRtHttpProxyInfoGetterByUpperLayer::
GetNextProxyInfo(const CRtString &aHost, WORD aPort, CRtHttpProxyInfo* &aPi)
{
	while (m_nIndex < MAX_INDEX) {
		if (!m_pServerIp[m_nIndex].empty() && 
			CRtHttpProxyManager::Instance()->
			CreateProxyInfo(m_pServerIp[m_nIndex], m_pType[m_nIndex], aPi))
		{
			return NEXT_SUCCESS;
		}
		m_nIndex++;
	}
	return NEXT_FAILED;
}

void CRtHttpProxyInfoGetterByUpperLayer::RegisterNotifaction(IRtObserver *aObserver)
{
	m_pObserver = aObserver;
}

void CRtHttpProxyInfoGetterByUpperLayer::SetServerHttp(const CRtString &aIpAndPort)
{
	m_pServerIp[0] = aIpAndPort;
}

void CRtHttpProxyInfoGetterByUpperLayer::SetServerHttps(const CRtString &aIpAndPort)
{
	m_pServerIp[1] = aIpAndPort;
}
